package com.wyw.hemerocallis.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 通过nacos下发动态路由配置，监听nacos中路由配置变更
 *
 * @author Mr Wu    yewen.wu.china@gmail.com
 * <p>
 * Update History:
 * Author        Time            Content
 */
@Slf4j
@Component
@DependsOn({"gatewayConfig"})
public class DynamicRouteServiceImplByNacos {
    /**
     * nacos配置服务
     */
    private ConfigService configService;

    private final DynamicRouteServiceImpl dynamicRouteService;

    public DynamicRouteServiceImplByNacos(DynamicRouteServiceImpl dynamicRouteService){
        this.dynamicRouteService = dynamicRouteService;
    }

    /**
     * Bean 在容器中构造完成之后执行该方法
     */
    @PostConstruct
    public void init() {
        log.info("gateway 路由初始化");
        try{
            //初始化Nacos配置客户端
            configService = initConfigService();
            if(null == configService) {
                log.info("初始化config service失败");
                return;
            }

            //通过Nacos Config并指定路由配置的路径去获取路由配置
            String configInfo = configService.getConfig(
              GatewayConfig.NACOS_ROUTE_DATA_ID,
              GatewayConfig.NACOS_ROUTE_GROUP,
              GatewayConfig.DEFAULT_TIMEOUT
            );

            log.info("获得gateway config:{}", configInfo);
            List<RouteDefinition> definitionList =
                    JSON.parseArray(configInfo, RouteDefinition.class);

            if(CollectionUtils.isNotEmpty(definitionList)) {
                for (RouteDefinition definition : definitionList) {
                    log.info("初始化gateway config:{}", definition.toString());
                    dynamicRouteService.addRouteDefinition(definition);
                }
            }

        } catch (Exception ex) {
            log.error("gateway 路由初始化异常{}", ex.getMessage(), ex);
        }

        //设置监听器
        dynamicRouteByNacosListerner(GatewayConfig.NACOS_ROUTE_DATA_ID,
                GatewayConfig.NACOS_ROUTE_GROUP);
    }

    /**
     * 初始化nacos config
     */
    private ConfigService initConfigService() {
        try {
            Properties properties = new Properties();
            properties.setProperty("serverAddr", GatewayConfig.NACOS_SERVER_ADDR);
            properties.setProperty("namespace", GatewayConfig.NACOS_NAMESPACE);
            return configService = NacosFactory.createConfigService(properties);
        } catch (Exception ex) {
            log.error("初始化gateway nacos config异常:{}", ex.getMessage(), ex);
            return null;
        }
    }

    /**
     * 监听Nacos下发的动态路由配置
     * @param dataId
     * @param group
     */
    private void dynamicRouteByNacosListerner(String dataId, String group) {
        try{
            //给Nacod Config客户端增加一个监听器
            configService.addListener(dataId, group, new Listener() {
                /**
                 * 自己提供线程池执行操作
                 *  一般情况下不需要我们管
                 */
                @Override
                public Executor getExecutor() {
                    return null;
                }

                /**
                 * 监听器收到配置更新
                 * @param configInfo    Nacos中最新的配置定义
                 */
                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("开始更新config:{}", configInfo);
                    List<RouteDefinition> definitionList =
                            JSON.parseArray(configInfo, RouteDefinition.class);
                    log.info("更新路由:{}", definitionList.toString());
                    dynamicRouteService.updateList(definitionList);
                }
            });
        } catch(Exception ex) {
            log.error("动态更新gateway config异常:{}", ex.getMessage(), ex);
        }
    }

}
